package com.hfi.restful.web.controller;

import com.fasterxml.jackson.annotation.JsonView;
import com.hfi.restful.dto.User;
import com.hfi.restful.dto.UserQueryCondition;
import com.hfi.restful.exception.ErrorCode;
import com.hfi.restful.exception.MyException;
import com.hfi.restful.response.Response;
import com.hfi.restful.validator.BeanValidator;
import com.hfi.restful.web.register.CustomUser;
import com.hfi.restful.web.register.CustomUserService;
import com.hfi.security.app.social.AppSignUpUtils;
import com.hfi.security.core.properties.SecurityProperties;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.apache.http.client.fluent.Request;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.security.core.Authentication;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.request.ServletWebRequest;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.io.UnsupportedEncodingException;
import java.util.*;

/**
 * @author ChangLiang
 * @date 2019/7/29
 */
@RestController
@RequestMapping("/user")
public class UserController {

    private Logger LOGGER = LoggerFactory.getLogger(getClass());

    // browser项目使用
/*    @Autowired
    private ProviderSignInUtils providerSignInUtils;*/

    @Autowired
    private SecurityProperties securityProperties;

    // app项目使用
    @Autowired
    private AppSignUpUtils appSignUpUtils;

    @Autowired
    private CustomUserService customUserService;

    @Autowired
    private RestTemplate restTemplate;

    private Logger logger = LoggerFactory.getLogger(getClass());

    @PostMapping("pushedListUnion")
    public String pushedListUnion2(@RequestParam String pageNum, @RequestParam String pageSize,
                                   @RequestParam Long userId) throws Exception {
        return pushedListUnion(pageNum, pageSize, userId);
    }

    private String pushedListUnion(String pageNum, String pageSize, Long userId) throws Exception {
        String userUrl = "http://127.0.0.1:8098/" + "pushmessage/pushedListUnion";
        String param = "?pageNum=" + pageNum + "&pageSize=" + pageSize + "&userId=" + userId;


        org.apache.http.client.fluent.Response execute = Request.Get(userUrl + param).connectTimeout(5000)
                .socketTimeout(5000).execute();
        // TODO: MyException
        int statusCode = execute.returnResponse().getStatusLine().getStatusCode();


        /// 模拟Apache fluent
        String responseBody = Request.Get(userUrl + param).connectTimeout(5000)
                .socketTimeout(5000).execute().returnContent().asString();//.handleResponse(new HfiResponseHandler());

        /// 模拟restTemplate
//        String responseBody = restTemplate.getForObject(userUrl + param, String.class);

        return responseBody;
    }



    /**
     * 第三方登录的注册页面
     *
     * @param customUser
     * @param request
     * @return
     */
    @PostMapping("/register")
    public Response register(CustomUser customUser, HttpServletRequest request) {
        Response response = new Response();
        ErrorCode result = ErrorCode.OK;
        try {
            // 模拟nickname就是唯一标识
            // 先去查询
            CustomUser user = customUserService.getByCustName(customUser.getCustName());
            if (user == null) {
                user = customUserService.registerCustomUser(customUser);
            }
            /// app 把业务user 和 第三方用户信息 绑定 插入到UserConnection表中
            appSignUpUtils.doPostSignUp(String.valueOf(user.getCustUserId()), new ServletWebRequest(request));
            /// browser 把业务user 和 第三方用户信息 绑定 插入到UserConnection表中
            //providerSignInUtils.doPostSignUp(String.valueOf(user.getCustUserId()), new ServletWebRequest(request));
        } catch (Exception e) {
            result = ErrorCode.ERROR;
        }
        response.setErrorcode(result.value);
        response.setValue(result.memo);
        return response;
    }

    @GetMapping("/me")
    public Authentication getCurrentUser(Authentication authentication, HttpServletRequest request) throws UnsupportedEncodingException {
        /// springmvc 会直接在SecurityContextHolder中去取
        //Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
//        return getResponse(authentication.getPrincipal());

        /// app使用 jwt自定义信息解析
        /*// 获取header中的Authentication的值
        String header = request.getHeader("Authorization");
        String accessToken = StringUtils.substringAfter(header, "Bearer ");
        // 解析的时候指定密钥
        Claims claims = Jwts.parser().setSigningKey(securityProperties.getOauth2().getJwtSigningKey().getBytes("UTF-8"))
                .parseClaimsJws(accessToken).getBody();
        String company = (String) claims.get("company");
        logger.info("自定义jwt信息 company:{}", company);*/

//        throw new RuntimeException("自定义runtime异常");

        /// 也可以直接返回
        return authentication;
    }

    /**
     * 删除用户
     *
     * @param id
     */
    @DeleteMapping("/{id:\\d+}")
    public void delete(@PathVariable String id) {
        LOGGER.info(id);
    }

    /**
     * 修改用户
     *
     * @param user
     * @param errors
     * @return
     */
    @PutMapping("/{id:\\d+}")
    public User update(@Valid @RequestBody User user, BindingResult errors) {
        if (errors.hasErrors()) {
            Map<String, String> validMessages = new HashMap<>(10);
            errors.getAllErrors().stream().forEach(
                    error -> {
                        FieldError fieldError = (FieldError) error;
                        validMessages.put(fieldError.getField(),error.getDefaultMessage());
                    }
            );
            // 如果检验错误，就返回错误信息
            throw new MyException(ErrorCode.BAD_REQUEST, validMessages);
        }
        // 否则返回正确信息
        System.out.println(user.getId());
        System.out.println(user.getUsername());
        System.out.println(user.getPassword());
        System.out.println(user.getBirthday());
        user.setId(1);
        return user;
    }

    /**
     * 创建用户
     * 这里我们使用BeanValidator来校验
     *
     * @param user
     * @return
     */
    @PostMapping
    public User create(@RequestBody User user) {

        Map<String, String> validateMap = BeanValidator.validateObject(user);
        if (MapUtils.isNotEmpty(validateMap)) {
            throw new MyException(ErrorCode.PARAM_VALIDATION_FAIL, validateMap);
        }
        LOGGER.info(user.getUsername());
        LOGGER.info(user.getPassword());
        LOGGER.info(user.getPassword());
        // 模拟用户创建
        user.setId(user.getId());
        return user;
    }

    /**
     * 查询用户详情
     *
     * @param id
     * @return
     */
    @GetMapping("/{id:\\d+}")
    @JsonView(Response.ResponseDetailView.class)
    public User getInfo(@ApiParam("用户id") @PathVariable String id) {

        // 模拟发生异常 会被全局异常处理器ControllerExceptionHandler会处理
//        throw new MyException(ErrorCode.ERROR,Arrays.asList("id:1"));

        // 模拟发生运行时异常 其不会被全局异常处理器ControllerExceptionHandler会处理
//        throw new RuntimeException("1");

        User user = new User();
        user.setUsername("tom");
        return user;
    }

    /**
     * 用户查询服务
     *
     * @param condition 用户查询条件的集合
     * @param pageable  分页参数
     * @return
     */
    @GetMapping
    @JsonView({Response.ResponseView.class})
    @ApiOperation(value = "用户查询服务")
    public List<User> query(UserQueryCondition condition, @PageableDefault Pageable pageable) {
        LOGGER.info(condition.toString());
        // 可以指定为分行显示
        LOGGER.info(ReflectionToStringBuilder.toString(condition, ToStringStyle.MULTI_LINE_STYLE));
        LOGGER.info(String.valueOf(pageable.getPageNumber()));
        LOGGER.info(String.valueOf(pageable.getPageSize()));
        LOGGER.info(String.valueOf(pageable.getSort()));
        User[] userArray = {new User(), new User(), new User()};
        return Arrays.asList(userArray);
    }
}
